#include "indiceapp.h"
#include <iostream>
#include <list>
#include <iomanip>
#include <cstdlib>
#include <cmath>
#include <QString>
#include <stdio.h>
#include <fstream>

using namespace std;
using std::setiosflags;
using std::ios;
using std::ofstream;
using std::cout;
using std::endl;
using std::setw;


IndiceApp::IndiceApp()
{
}


/**
  *@brief calculaDIDI
  *@param pcurta periodo para calculo da media curta
  *@param pInterm periodo para calculo da media intermediaria
  *@param plonga periodo para calculo da media longa
  *@param lista lista contendo os dados de entrada ( data e valor de fechamento da acao)
  *@return lista lista com todos os campos DIDI Index calculados
  */
list<Indice*> IndiceApp:: calculaDIDI ( int pcurta, int pInterm, int plonga, list<Indice*> lista )
{
    /// Introducao ao Metodo e variaveis

    /// os periodos seguem as seguintes regras:
    /// todos sao > 0 e diferentes entre si
    /// o periodo para media pcurta deve ser menor e diferentes das demais
    /// o periodo para media pInterm deve estar entre a curta e a longa
    if (  ( ( pcurta <= 0) || ( pInterm <= 0) || (plonga <=0)) ||
          ( (pcurta >= pInterm) || (pcurta>= plonga) || (pInterm >= plonga) ))
    {
        cerr << "Periodo(s) incorreto(s)." << endl;
        lista.clear(); // caso erro, retorna lista vazia
        return lista;
    }

    /// este metodo percorre a lista de entrada na ordem inversa
    /// utilizando os interadores de suporte iter3, iter4,iter5 e iter6
    list<Indice*>::iterator iter3 = lista.end(); // interador item atual
    list<Indice*>::iterator iter4 = lista.end(); // interador item anterior ref a media curta
    list<Indice*>::iterator iter5 = lista.end(); // interador item anterior ref a media interm
    list<Indice*>::iterator iter6 = lista.end(); // interador item anterior ref a media longa

    // sobe uma posicao para iniciar na posicao correta na lista
    iter3--;
    iter4--;
    iter5--;
    iter6--;

    //somatorios da medias
    double soma3 = 0.0;
    double soma8 = 0.0;
    double soma20 = 0.0;


    /// contador 'm' para disparar o calculo das tres medias em posicoes diferentes da lista
    /// conforme o periodo escolhido
    int m = 0;   //contador

    /// atual, ant, ant8 e ant20 sao objetos da lista refenciados pelos iteradores.\n
    /// Cada iterador eh decrementado (subindo na lista) de maneira diferente, com excecao
    /// de iter3, que faz o loop principal. Os outros iteradores iter4, iter5 e iter6 comecam
    /// a ser decrementados conf. a lista alcanca cada o valor do periodo pcurta, pInterm e plonga.
    /// nessa ordem. \n Isso faz parte da media movel, onde cada somatorio da media movel deve pegar
    /// o proximo valor atual (atual->fecham) e subtrair o mais antigo( v3, v8 e v20). \n O valor antigo
    /// se inicia da base da lista,segue a logica dos iteradores e se atualiza a cada loop, recebendo
    /// os valores do campo 'fecham' de ant, ant8 e ant20, respectivamente.
    Indice *atual = new Indice();   // objeto atual da lista
    Indice *ant = new Indice();     // objeto referente a 'pcurta' objetos anteriores
    Indice *ant8 = new Indice();    // objeto referente a 'pInterm' objetos anteriores
    Indice *ant20 = new Indice();   // objeto referente a 'plonga' objetos anteriores


    /// v3,v8 e v20 sao valores antigos a subtrair dos somatorios moveis soma3, soma8 soma20 respect. \n\n
    double v3 = 0.0;
    double v8 = 0.0;
    double v20 = 0.0;

    /// Descricao do algoritimo principal \n \n \n
    /// Enquanto a lista nao esta no topo
    while ( atual != lista.front() )
    {
        /// atualiza iteradores da lista
        atual = *iter3;
        ant = *iter4;
        ant8 = *iter5;
        ant20 = *iter6;


        /// atualiza valores a subtrair dos somatorios moveis
        v3 = ant->fecham;
        v8 = ant8->fecham;
        v20 = ant20->fecham;

        /// comeca os calculos das media moveis ma3, ma8 e ma20, lembrando que o
        /// contador 'm' comeca de zero, NAO de 1, entao os periodos sao diminuidos de 1
        /// nas comparacoes if.

        /// se o contador 'm' eh menor igual a curta apenas incrementa os somatorios moveis
        if (m <= ( pcurta-1))
        {
            soma3 += atual->fecham; //cria os somatorios para media3,8 e 20
            soma8 += atual->fecham;
            soma20 += atual->fecham;

            /// se for igual ao pcurto, faca a media curta ma3
            if (m == ( pcurta-1))
                atual->ma3 = (soma3 / pcurta);
        }

        /// se estiver entre a media curte e media intermediaria
        /// continue os somatorios, faca a media curta e decremente o iterador iter4
        if ( ( m > ( pcurta-1) ) && ( m <= (pInterm-1)) )
        {
            soma3 = (soma3 - v3) + atual->fecham;
            soma8 += atual->fecham;
            soma20 += atual->fecham;
            atual->ma3 = (soma3 / pcurta);
            iter4--;

            /// se contador for igual a pInterm, faca a media intermediaria ma8
            if (m == (pInterm-1))
                atual->ma8 = (soma8 / pInterm );
        }

        /// se o contador 'm' estiver entre a media interm e a media longa
        /// continue os somatorios, faca as medias ma3, ma8 e decremente iter4 e iter5
        if ( ( m > (pInterm-1) ) && ( m <= (plonga-1))  )
        {
            soma3 = (soma3 - v3) + atual->fecham;
            soma8 = (soma8 - v8)+ atual->fecham;
            soma20 += atual->fecham;
            atual->ma3 = (soma3 / pcurta);
            atual->ma8 = (soma8 / pInterm );
            iter4--;
            iter5--;

            /// se contador for igual plonga, faca a media longa ma20, faca a media mais
            /// proxima e mais distante da base(atual->curta)e(atual->longa)
            /// e faca a linha base (atual->base) contante = 1
            if (m == (plonga-1))
            {
                atual->ma20 = (soma20 / plonga);
                atual->curta = (atual->ma3 /  atual->ma8);
                atual->longa = (atual->ma20 / atual->ma8);
                atual->base = 1;
            }
        }

        /// se contador for maior que plonga faca todos os calculos
        /// anteriores e decremente os iteradores
        if (m > (plonga-1))
        {
            soma3 = (soma3 - v3) + atual->fecham;
            soma8 = (soma8 - v8)+ atual->fecham;
            soma20 = (soma20 - v20) + atual->fecham;

            atual->ma3 = (soma3 / pcurta);
            atual->ma8 = (soma8 / pInterm);
            atual->ma20 = (soma20 / plonga);

            atual->curta = (atual->ma3 /  atual->ma8);
            atual->longa = (atual->ma20 / atual->ma8);
            atual->base = 1;

            iter4--;
            iter5--;
            iter6--;

        }

        /// continua o loop principal e incrementa o contador
        iter3--;
        m++;

    }//fim do while

    /// retorna a lista com todos os campos calculados
    return (lista);

}

